package com.springframework.boot.awesome.annotation.arch.aspect;

import com.springframework.boot.awesome.annotation.arch.exception.FTPUrlIllegalException;
import com.springframework.boot.awesome.annotation.arch.exception.FrequencyLimitException;
import com.springframework.boot.awesome.annotation.arch.exception.TimeoutLimitException;
import com.springframework.boot.awesome.annotation.ftp.MonitorFTPFile;
import com.springframework.boot.awesome.annotation.arch.util.ReflectUtil;
import com.springframework.boot.awesome.annotation.arch.entity.FTPConfig;
import com.springframework.boot.awesome.annotation.arch.util.MonitorUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
@Aspect
public class MonitorFTPFileAspect {
    private static String ftp_url_regex = "(ftp|sftp):\\/\\/(\\S*):(\\S*)@((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})" +
            "\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2}):" +
            "([0-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{4}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])(\\/(\\w+\\/?)+$)";
    private static Pattern pattern = Pattern.compile(ftp_url_regex);

    @Pointcut("@annotation(com.springframework.boot.awesome.annotation.ftp.MonitorFTPFile)")
    public void pointcut(){

    }

    @Around("pointcut() && @annotation(monitorFTPFile) ")
    public void around(ProceedingJoinPoint proceedingJoinPoint, MonitorFTPFile monitorFTPFile) throws Throwable {
        try{
            String url = monitorFTPFile.url();
            Matcher matcher = pattern.matcher(url);
            if(!matcher.matches()){
                throw new FTPUrlIllegalException("FTP or SFTP url is illegal, demo: ftp(sftp)://{username}:{password}@{ip}:{port}{absolute path}");
            }
            long millisecondsFrequency = monitorFTPFile.millisecondsFrequency();
            if(millisecondsFrequency < 0 || millisecondsFrequency > 10 * 60 * 1000){
                throw new FrequencyLimitException("millisecondsFrequency is not in limit, should: 10 * 60 * 1000 > frequency > 0");
            }
            long millisecondsTimeout = monitorFTPFile.millisecondsTimeout();
            if(millisecondsTimeout < 0 || millisecondsTimeout > 2 * 60 * 60 * 1000){
                throw new TimeoutLimitException("millisecondsTimeout is not in limit, should: 2 * 60 * 60 * 1000 > timeout > 0");
            }

            Object monitorObj = ReflectUtil.createInstanceByPackage(monitorFTPFile.monitorClassPackage());
            Class[] paramsClassArgs = new Class[]{List.class};
            Method handleFileMethod = ReflectUtil.getMethod(monitorFTPFile.monitorClassPackage(), "monitorFile", paramsClassArgs);

            FTPConfig ftpConfig = getFTPConfigByFtpString(url);
            MonitorUtil.monitorFileNameList(millisecondsFrequency, handleFileMethod, monitorObj, ftpConfig, millisecondsTimeout);
        } catch (Exception e) {
            e.printStackTrace();
            if(StringUtils.isEmpty(monitorFTPFile.exceptionHandlerClassPackage())){
                throw e;
            }else{
                try{
                    Object exceptionHandlerObj = ReflectUtil.createInstanceByPackage(monitorFTPFile.exceptionHandlerClassPackage());
                    Class[] paramsClassArgs = new Class[]{e.getClass()};
                    Method exceptionHandlerMethod = ReflectUtil.getMethod(monitorFTPFile.exceptionHandlerClassPackage(), "handle" + e.getClass().getSimpleName(), paramsClassArgs);
                    Object[] arguments = new Object[]{e};
                    exceptionHandlerMethod.invoke(exceptionHandlerObj, arguments);
                }catch (Exception e1){
                    throw e1;
                }
            }
        }
        proceedingJoinPoint.proceed();
    }

    public static FTPConfig getFTPConfigByFtpString(String url) {
        String protocal = StringUtils.substringBefore(url, "://");

        String tempStr = protocal + "://";
        String tempUrl = StringUtils.replace(url, tempStr, "");
        String username = StringUtils.substringBefore(tempUrl, ":");

        tempStr = tempStr + username + ":";
        tempUrl = StringUtils.replace(url, tempStr, "");
        String password = StringUtils.substringBeforeLast(tempUrl, "@");

        tempStr = tempStr + password + "@";
        tempUrl = StringUtils.replace(url, tempStr, "");
        String ip_port = StringUtils.substringBefore(tempUrl, "/");
        tempStr = tempStr + ip_port;

        String path = StringUtils.replace(url, tempStr, "");
        String port = StringUtils.substringAfter(ip_port, ":");
        String ip = StringUtils.substringBefore(ip_port, ":");
        return new FTPConfig(protocal, username, password, ip, port, path);
    }

}